﻿using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Diagnostics;
using System.Collections.Generic;

namespace CorpStoreServer
{
    public class Log
    {
        private string _logFn;
        private bool _initialized = false;
        private long _numLinesSoFar = 0;
        private const long MAX_LINES_PER_FILE = 5000;

        /// <summary>
        /// This event gets fired whenever a new log entry is made.  Your app may optionally handle this event to be able to 
        /// display log information on its own UI.
        /// </summary>
        public event Action<string> OnLogEntry;

        /// <summary>
        /// You MUST call this function before attempting to use any of the other log functions.  This will
        /// initialize the logger so that log entries are routed to 'logFn', where 'logFn' is the full path
        /// and filename of the log file to write to.  Set 'appendToExisting' to true if you want to append
        /// to any existing log file.  Set it to false to immediately back it up to *.bak and then start 
        /// writing to a new log file with name 'logFn'.  'errStr' will get set to any error strings encountered
        /// during this init process.
        /// </summary>
        /// <param name="logFn">full path + filename of log file; directory will be created if necessary</param>
        /// <param name="appendToExisting">true to append to existing file; false to rename existing to *.bak and start writing to new file</param>
        /// <param name="errStr">any error string encountered</param>
        /// <returns>true if init succeeded</returns>
        public bool Init(string logFn, bool appendToExisting, out string errStr)
        {
            errStr = "";

            try
            {
                if (!logFn.EndsWith(".log", StringComparison.OrdinalIgnoreCase))
                    logFn = logFn + ".log";

                this._logFn = logFn;

                // create directory for log file if necessary
                string strLogPath = Path.GetDirectoryName(logFn);
                if (!Directory.Exists(strLogPath))
                {
                    Directory.CreateDirectory(strLogPath);
                }

                // back up existing log file if necessary
                if (!appendToExisting && File.Exists(logFn))
                {
                    // attempt to rename it 
                    string newFn = logFn.Replace(".log", ".bak");
                    File.Delete(newFn); // delete any prior backups
                    File.Move(logFn, newFn);
                }
                else
                    _numLinesSoFar = GenLib.CountLines(logFn, out errStr);

                _initialized = true;
                LogInfo("vvvvvvvvvvvvvvvvvvvv Log started at " + logFn + "; exe = " + GenLib.AppExeFn() + " vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv");
            }
            catch (Exception ex)
            {
                errStr = "Unhandled exception while initializing log system: " + ex.Message;
            }

            return _initialized;
        }


        public void Shutdown()
        {
            if (_initialized)
            {
                LogInfo("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
            }

            _initialized = false;
        }


        public void LogInfo(string msg, params object[] parms)
        {
            writeToFile("INFO", msg, parms);
        }

        public void LogErr(string msg, params object[] parms)
        {
            writeToFile("ERR!", msg, parms);
        }

        private void writeToFile(string logType, string msg, params object[] parms)
        {
            string strMsgWithParms = string.Format(msg, parms);
            string strLine = string.Format("{0} {1} {2}", DateTime.Now.ToString("dd HH:mm:ss.fff"), logType, strMsgWithParms);

            if (OnLogEntry != null) OnLogEntry(strLine);
            Debug.WriteLine(strLine);
            if (_initialized)
            {
                File.AppendAllText(_logFn, string.Format("{0}\r\n", strLine));
                Console.WriteLine("{0} {1}", logType, strMsgWithParms);
            }

            // rotate log files if necessary
            _numLinesSoFar++;
            if (_numLinesSoFar >= MAX_LINES_PER_FILE)
                rotateFiles();
        }


        private void rotateFiles()
        {
            try
            {
                // attempt to rename current log file 
                string newFn = _logFn.Replace(".log", ".bak");
                File.Delete(newFn);
                File.Move(_logFn, newFn);

                // finally delete original log file to start over
                File.Delete(_logFn);
                _numLinesSoFar = 0;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Unhandled exception while rotating logs: " + ex.Message);
                _numLinesSoFar = 0;
            }
        }
    }
}
